#pragma once

#include<vector>
#include<pthread.h>
#include<semaphore.h>

template<class T>
class RingQueue
{
  private:
    //临界区
    std::vector<T> bq;
    int cap;   //总空间
    //信号量
    sem_t data_sem;
    sem_t space_sem;
    //下标
    int c_index;
    int p_index;
    //锁
    pthread_mutex_t c_lock;
    pthread_mutex_t p_lock;

  public:
    RingQueue(int _cap)
      :cap(_cap),
      c_index(0),
      p_index(0)
    {
      bq.resize(cap);
  
      sem_init(&space_sem,0,cap);
      sem_init(&data_sem,0,0);

      pthread_mutex_init(&c_lock,nullptr);
      pthread_mutex_init(&p_lock,nullptr);
    }
    void Put(const T& data)
    {
      sem_wait(&space_sem);
      //一定成功
      pthread_mutex_lock(&p_lock);    //要对下标进行访问

      bq[p_index]=data;
      p_index++;
      if(p_index>cap)
        p_index%=cap;

      pthread_mutex_unlock(&p_lock);

      sem_post(&data_sem);
    }
    void Get(T* s)
    {
        sem_wait(&data_sem);
        //一定成功
        pthread_mutex_lock(&c_lock);

        *s=bq[c_index];
        c_index++;
        if(c_index>cap)
          c_index%=cap;

        pthread_mutex_unlock(&c_lock);

        sem_post(&space_sem);
    }
    ~RingQueue()
    {
      pthread_mutex_destroy(&c_lock);
      pthread_mutex_destroy(&p_lock);

      sem_destroy(&space_sem);
      sem_destroy(&data_sem);
    }
};
